/**
 * 
 */
package org.wltea.analyzer;

/**
 * IK Analyzer v3.2 语义单元（词元） *
 * 
 * @author 林良益
 * 
 */
public final class Lexeme implements Comparable<Lexeme> {
	// lexemeType常量
	// 普通词元
	public static final int TYPE_CJK_NORMAL = 0;
	// 未知的
	public static final int TYPE_CJK_UNKNOWN = 1;
	// 未知的
	public static final int TYPE_CJK_MIX = 2;
	// 数词
	public static final int TYPE_NUM = 3;
	// 英文
	public static final int TYPE_LETTER = 4;
	//
	public static final int TYPE_PHRASE = 5;
	//
	public static final int TYPE_LETTER_MIX = 6;
	//
	public static final int TYPE_CONNECTOR = 7;
	//
	public static final int TYPE_CONNECTOR_MIX = 8;
	//
	public static final int DICT_NOT_MATCH = 0;
	public static final int DICT_IN_BASE = 1;
	public static final int DICT_IN_EXT = 2;
	// 词元的起始位移
	private int offset;
	// 词元的相对起始位置
	private int begin;
	// 词元的长度
	private int length;
	// 词元文本
	private String lexemeText;
	// 词元类型
	private int lexemeType;
	// 词典匹配情况
	private int hitMatch = DICT_NOT_MATCH;
	// 当前词元的前一个词元
	private Lexeme prev;
	// 当前词元的后一个词元
	private Lexeme next;

	public Lexeme(int offset, int begin, int length, int lexemeType) {
		this.offset = offset;
		this.begin = begin;
		if (length < 0) {
			throw new IllegalArgumentException("length < 0");
		}
		this.length = length;
		this.lexemeType = lexemeType;
	}

	/*
	 * 判断词元相等算法 起始位置偏移、起始位置、终止位置相同
	 * 
	 * @see java.lang.Object#equals(Object o)
	 */
	@Override
	public boolean equals(Object o) {
		if (o == null) {
			return false;
		}

		if (this == o) {
			return true;
		}

		if (o instanceof Lexeme) {
			Lexeme other = (Lexeme) o;
			if (this.offset == other.getOffset()
			        && this.begin == other.getBegin()
			        && this.length == other.getLength()) {
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}

	/*
	 * 词元哈希编码算法
	 * 
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		int absBegin = getBeginPosition();
		int absEnd = getEndPosition();
		return (absBegin * 37) + (absEnd * 31)
		        + ((absBegin * absEnd) % getLength()) * 11;
	}

	/*
	 * 词元在排序集合中的比较算法
	 * 
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	@Override
	public int compareTo(Lexeme other) {
		// 起始位置优先
		if (this.begin < other.getBegin()) {
			return -1;
		} else if (this.begin == other.getBegin()) {
			// 词元长度优先
			if (this.length > other.getLength()) {
				return -1;
			} else if (this.length == other.getLength()) {
				return 0;
			} else {// this.length < other.getLength()
				return 1;
			}

		} else {// this.begin > other.getBegin()
			return 1;
		}
	}

	/**
	 * 判断词元是否彼此包含
	 * 
	 * @param other
	 * @return boolean true 完全包含 ， false 可能不相交 或者 相交但不包含
	 */
	public boolean isOverlap(Lexeme other) {
		if (other != null) {
			if (this.getBeginPosition() <= other.getBeginPosition()
			        && this.getEndPosition() >= other.getEndPosition()) {
				return true;

			} else if (this.getBeginPosition() >= other.getBeginPosition()
			        && this.getEndPosition() <= other.getEndPosition()) {
				return true;

			} else {
				return false;
			}
		}
		return false;
	}

	public int getOffset() {
		return offset;
	}

	public void setOffset(int offset) {
		this.offset = offset;
	}

	public int getBegin() {
		return begin;
	}

	/**
	 * 获取词元在文本中的起始位置
	 * 
	 * @return int
	 */
	public int getBeginPosition() {
		return offset + begin;
	}

	public void setBegin(int begin) {
		this.begin = begin;
	}

	public int getEnd() {
		return begin + length;
	}

	/**
	 * 获取词元在文本中的结束位置
	 * 
	 * @return int
	 */
	public int getEndPosition() {
		return offset + begin + length;
	}

	/**
	 * 获取词元的字符长度
	 * 
	 * @return int
	 */
	public int getLength() {
		return this.length;
	}

	public void setLength(int length) {
		if (this.length < 0) {
			throw new IllegalArgumentException("length < 0");
		}
		this.length = length;
	}

	/**
	 * 获取词元的文本内容
	 * 
	 * @return String
	 */
	public String getLexemeText() {
		if (lexemeText == null) {
			return "";
		}
		return lexemeText;
	}

	public void setLexemeText(String lexemeText) {
		if (lexemeText == null) {
			this.lexemeText = "";
			this.length = 0;
		} else {
			this.lexemeText = lexemeText;
			this.length = lexemeText.length();
		}
	}

	/**
	 * 获取词元类型
	 * 
	 * @return int
	 */
	public int getLexemeType() {
		return lexemeType;
	}

	public void setLexemeType(int lexemeType) {
		this.lexemeType = lexemeType;
	}

	@Override
	public String toString() {
		StringBuffer strbuf = new StringBuffer();
		strbuf.append(this.getBeginPosition()).append("-")
		        .append(this.getEndPosition());
		strbuf.append(" : ").append(this.lexemeText).append(" : \t");
		switch (lexemeType) {
		case TYPE_CJK_NORMAL:
			strbuf.append("CJK_NORMAL");
			break;
		case TYPE_CJK_UNKNOWN:
			strbuf.append("UNKNOWN");
			break;
		case TYPE_CJK_MIX:
			strbuf.append("CJK_MIX");
			break;
		case TYPE_NUM:
			strbuf.append("NUMEBER");
			break;
		case TYPE_LETTER:
			strbuf.append("LETTER");
			break;
		case TYPE_LETTER_MIX:
			strbuf.append("LETTER_MIX");
			break;
		case TYPE_PHRASE:
			strbuf.append("PHRASE");
			break;
		case TYPE_CONNECTOR:
			strbuf.append("CONNECTOR");
			break;
		case TYPE_CONNECTOR_MIX:
			strbuf.append("CONNECTOR_MIX");
			break;
		}
		strbuf.append(" : \t").append(hitMatch);
		return strbuf.toString();
	}

	Lexeme getPrev() {
		return prev;
	}

	void setPrev(Lexeme prev) {
		this.prev = prev;
	}

	Lexeme getNext() {
		return next;
	}

	void setNext(Lexeme next) {
		this.next = next;
	}

	public boolean isInExtDict() {
		return DICT_IN_EXT == hitMatch;
	}

	public boolean isInBaseDict() {
		return DICT_IN_BASE == hitMatch;
	}

	public boolean isInDict() {
		return DICT_IN_EXT == hitMatch || DICT_IN_BASE == hitMatch;
	}

	public void setInBaseDict() {
		hitMatch = DICT_IN_BASE;
	}

	public void setInExtDict() {
		hitMatch = DICT_IN_EXT;
	}

	public boolean isCJK() {
		return lexemeType == TYPE_CJK_NORMAL || lexemeType == TYPE_CJK_UNKNOWN;
	}

	public boolean isPhrase() {
		return lexemeType == TYPE_PHRASE || lexemeType == TYPE_CJK_MIX;
	}

	public boolean isLetterMix() {
		return lexemeType == TYPE_LETTER_MIX;
	}

	public boolean isConnectorMix() {
		return lexemeType == TYPE_CONNECTOR_MIX;
	}

	public boolean isLetter() {
		return lexemeType == TYPE_LETTER;
	}

	public boolean isLetterOrNum() {
		return lexemeType == TYPE_LETTER || lexemeType == TYPE_NUM
		        || lexemeType == TYPE_LETTER_MIX;
	}

}